﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using CoiffeurProject.Utils;
using CoiffeurProject.DBMS;
using CoiffeurProject.UserControls;
using System.ComponentModel;

namespace CoiffeurProject.Screens
{
    public partial class CustomerScreen : Window
    {
        internal SVCustomerEntry Selected;

        Database db;
        List<SVCustomerEntry> customers;
        CustomerDetailsPanel panel;

        TicketButton list_btn, panel_btn, add_btn, modify_btn, delete_btn;
        ImageBrush panel_state_bg, no_panel_state_bg;

        ScreenState screenState;

        SearchBar searchBox;
        LettersDashSlider slider;
        CustomersTableHeaders headers;
        ScrollViewer svWithPanel, svWithList, svNotifications;
        Grid svWithPanelGrid, svWithListGrid, svNotificationsGrid;
        NotificationBubble notification_bubble;
        CustomersFiltersPanel filter_panel;
        FilterParameter last_ordering_parameter = FilterParameter.None;
        
        public CustomerScreen(Database db)
        {
            this.db = db;

            screenState = ScreenState.CustomerList;

            InitializeComponent();

            InitializeNotificationsSV();
            InitializeSVForListVisualization();
            InitializeSVForCustomerPanelVisualization();

            InitializeUserControlComponents();

            AddCustomersToSV();
           
            slider = new LettersDashSlider(0, 2, 3, 0);
            slider.LeftArrow.Click +=new RoutedEventHandler(delegate(object s, RoutedEventArgs a) { MoveSVTo(slider.SelectedLetter); });
            slider.RightArrow.Click += new RoutedEventHandler(delegate(object s, RoutedEventArgs a) { MoveSVTo(slider.SelectedLetter); });
            main_container.Children.Add(slider.MainContainer);

            headers = new CustomersTableHeaders(this, 1, 0, 3, 0);
            main_container.Children.Add(headers.MainContainer);

            filter_panel = new CustomersFiltersPanel(this);
            main_container.Children.Add(filter_panel.MainContainer);

            this.Show();
        }

        private void InitializeSVForCustomerPanelVisualization()
        {
            svWithPanel = new ScrollViewer()
            {
                Name = "svWithPanel",
                Height = 907,
                Width = 380,
                HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                VerticalAlignment = System.Windows.VerticalAlignment.Top,
                Margin = new Thickness(51, 80, 0, 0)
            };

            svWithPanelGrid = new Grid()
            {
                Name = "svWithPanelGrid",
                Width = 364,
                HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                VerticalAlignment = System.Windows.VerticalAlignment.Top
            };

            svWithPanel.Content = svWithPanelGrid;

            Grid.SetRow(svWithPanel, 1);
        }

        private void InitializeSVForListVisualization()
        {
            svWithList = new ScrollViewer()
            {
                Name = "svWithList",
                Height = 907,
                Width = 1423,
                HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                VerticalAlignment = System.Windows.VerticalAlignment.Top,
                Margin = new Thickness(51, 80, 0, 0)
            };

            svWithListGrid = new Grid()
            {
                Name = "svWithListGrid",
                Width = 1388,
                HorizontalAlignment = System.Windows.HorizontalAlignment.Left
            };

            svWithList.Content = svWithListGrid;

            Grid.SetRow(svWithList, 1);
            Grid.SetColumnSpan(svWithList, 3);
            main_container.Children.Add(svWithList);
        }

        private void InitializeNotificationsSV()
        {
            notification_bubble = new NotificationBubble(new Thickness(294, 572, 0, 0),
                db.Notifications.CustomersNotifications.Count, 38, 38, 1, 2);

            main_container.Children.Add(notification_bubble.MainContainer);

            svNotifications = new ScrollViewer()
            {
                Height = 357,
                Width = 370,
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top,
                Margin = new Thickness(292, 627, 0, 0)
            };

            svNotificationsGrid = new Grid()
            {
                Width = 345,
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top
            };

            svNotifications.Content = svNotificationsGrid;

            Grid.SetRow(svNotifications, 1);
            Grid.SetColumn(svNotifications, 2);

            AddNotificationToSV();

            main_container.Children.Add(svNotifications);
        }

        private void InitializeUserControlComponents()
        {
            var exit_button = new CloseButton(this, new Thickness(625, 40, 0, 0), 0, 2);

            main_container.Children.Add(exit_button.MainContainer);

            searchBox = new SearchBar(new Thickness(32, 41, 0, 0), 0, 0);
            searchBox.TextBox.TextChanged += new TextChangedEventHandler(
                delegate(object sender, TextChangedEventArgs e)
                {
                    ResetSVGrid();

                    FilterCustomers(last_ordering_parameter);
                });

            main_container.Children.Add(searchBox.MainContainer);

            #region Ticket Buttons
            
            list_btn = new TicketButton(new Thickness(282,15,0,0), "Lista",
                @"pack://application:,,,/CoiffeurProject;component/Images/Customer/Icons/list.PNG",
                delegate(object sender, RoutedEventArgs e) {
                    if (screenState == ScreenState.CustomerPanel)
                    {
                        screenState = ScreenState.CustomerList;
                        StateHasChanged();
                    }
                });

            Grid.SetColumn(list_btn.MainContainer, 2);
            Grid.SetRow(list_btn.MainContainer, 1);

            main_container.Children.Add(list_btn.MainContainer);

            panel_btn = new TicketButton(new Thickness(282 + 124, 15, 0, 0), "Pannello",
                @"pack://application:,,,/CoiffeurProject;component/Images/Customer/Icons/panel.PNG",
                delegate(object sender, RoutedEventArgs e) {
                    if (screenState == ScreenState.CustomerList)
                    {
                        screenState = ScreenState.CustomerPanel;
                        StateHasChanged();
                    }
                });

            Grid.SetColumn(panel_btn.MainContainer, 2);
            Grid.SetRow(panel_btn.MainContainer, 1);

            main_container.Children.Add(panel_btn.MainContainer);

            add_btn = new TicketButton(new Thickness(282, 153, 0, 0), "Nuovo cliente",
                @"pack://application:,,,/CoiffeurProject;component/Images/Customer/Icons/add.PNG",
                delegate(object sender, RoutedEventArgs e) {
                    CustomerForm form = new CustomerForm(db);
                    this.DisableForegroundWindow(form);
                    form.Closing += new System.ComponentModel.CancelEventHandler(delegate(object s, CancelEventArgs ee) {
                        customers.Add(new SVCustomerEntry(this, db.Customers.List.Last(), 0, 0));
                        FilterCustomers(last_ordering_parameter);
                        MoveSVTo('z');
                    });
                });

            Grid.SetColumn(add_btn.MainContainer, 2);
            Grid.SetRow(add_btn.MainContainer, 1);

            main_container.Children.Add(add_btn.MainContainer);

            modify_btn = new TicketButton(new Thickness(282 + 128, 153, 0, 0), "Modifica",
                @"pack://application:,,,/CoiffeurProject;component/Images/Customer/Icons/modify.PNG",
                delegate(object sender, RoutedEventArgs e) {
                    if (Selected != null)
                    {
                        var form = new CustomerForm(db, Selected.LinkedCustomer);

                        this.DisableForegroundWindow(form);

                        form.Closed +=new EventHandler(delegate(object s, EventArgs ee) {
                            panel.ChangeLinkedCustomer(Selected.LinkedCustomer);
                            Selected.UpdateData();
                        });
                    }
                });

            Grid.SetColumn(modify_btn.MainContainer, 2);
            Grid.SetRow(modify_btn.MainContainer, 1);

            main_container.Children.Add(modify_btn.MainContainer);

            delete_btn = new TicketButton(new Thickness(282 + 1 + 128 * 2, 153, 0, 0), "Elimina",
                @"pack://application:,,,/CoiffeurProject;component/Images/Customer/Icons/delete.PNG",
                delegate(object sender, RoutedEventArgs e) {
                    if (Selected != null)
                    {
                        panel.HidePanel();
                        db.Customers.DeleteCustomer(Selected.LinkedCustomer);
                        customers.Remove(Selected);
                        Selected = null;
#warning forse da togliere il Reset da qui
                        ResetSVGrid();
                        FilterCustomers(FilterParameter.None);
                    }
                });

            Grid.SetColumn(delete_btn.MainContainer, 2);
            Grid.SetRow(delete_btn.MainContainer, 1);

            main_container.Children.Add(delete_btn.MainContainer);

            #endregion

            #region Backgrounds

            panel_state_bg = new ImageBrush() 
            {
                ImageSource = new BitmapImage(new Uri(
                    @"pack://application:,,,/CoiffeurProject;component/Images/Customer/background_with_panel.JPG")),
                Stretch = Stretch.Uniform
            };

            no_panel_state_bg = new ImageBrush()
            {
                ImageSource = new BitmapImage(new Uri(
                    @"pack://application:,,,/CoiffeurProject;component/Images/Customer/background_without_panel.JPG")),
                Stretch = Stretch.Uniform
            };

            #endregion
        }

        private void ResetSVGrid()
        {
            svWithPanelGrid.Children.Clear();
            svWithPanelGrid.RowDefinitions.Clear();

            svWithListGrid.Children.Clear();
            svWithListGrid.RowDefinitions.Clear();
        }

        private void AddNotificationToSV()
        {
            for (int i = 0; i < db.Notifications.CustomersNotifications.Count; i++)
            {
                var not = db.Notifications.CustomersNotifications[i];

                svNotificationsGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(36) });
                int rows_num = svNotificationsGrid.RowDefinitions.Count;

                var entry = new SVCustomerNotEntry(this, not, rows_num - 1, 0);
                svNotificationsGrid.Children.Add(entry.MainContainer);
            }
        }

        private void AddCustomersToSV()
        {
            if (customers == null)
            {
                customers = new List<SVCustomerEntry>();

                var ordered_customer_list = db.Customers.List.OrderBy(c => c.FullName).ToList();

                for (int i = 0; i < db.Customers.List.Count; i++)
                {
                    customers.Add(new SVCustomerEntry(this, ordered_customer_list[i], 0, 0));
                    switch (screenState)
                    {
                        case ScreenState.CustomerList:
                            AddCustomerToGrid(svWithListGrid, customers[i]);
                            break;
                        default:
                            AddCustomerToGrid(svWithPanelGrid, customers[i]);
                            break;
                    }
                }
            }
            else
            {
                for (int i = 0; i < customers.Count; i++)
                {
                    switch (screenState)
                    {
                        case ScreenState.CustomerList:
                            AddCustomerToGrid(svWithListGrid, customers[i]);
                            break;
                        default:
                            AddCustomerToGrid(svWithPanelGrid, customers[i]);
                            break;
                    }
                }
            }
            
        }

        internal void AddCustomersToSV(List<SVCustomerEntry> filtered_customers)
        {
            ResetSVGrid();

            for (int i = 0; i < filtered_customers.Count; i++)
            {
                switch (screenState)
                {
                    case ScreenState.CustomerList:
                        AddCustomerToGrid(svWithListGrid, filtered_customers[i]);
                        break;
                    default:
                        AddCustomerToGrid(svWithPanelGrid, filtered_customers[i]);
                        break;
                }
            }
        }

        internal static void AddCustomerToGrid(Grid grid, SVCustomerEntry customer)
        {
            grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(54) });
            int rows_num = grid.RowDefinitions.Count;

            Grid.SetRow(customer.MainContainer, rows_num - 1);
            grid.Children.Add(customer.MainContainer);
        }

        internal void ChangeSelected(SVCustomerEntry customer)
        {
            if (Selected != null) Selected.ToggleSelected();

            Selected = customer;

            if (panel == null)
            {
                panel = new CustomerDetailsPanel(customer.LinkedCustomer);
                main_container.Children.Add(panel.MainContainer);
                if (screenState == ScreenState.CustomerList) panel.MainContainer.Visibility = Visibility.Hidden;
            }
            else
            {
                if (screenState == ScreenState.CustomerPanel)
                    panel.MainContainer.Visibility = Visibility.Visible;
                panel.ChangeLinkedCustomer(customer.LinkedCustomer);
            }
        }

        public void MoveSVTo(char letter)
        {
            int offset = 53;
            var current_customer_list = GetFilteredCustomersList();

            if (current_customer_list == null) return;

            var index = current_customer_list.FindIndex(c => c.LinkedCustomer.Name.ToLower()[0] == letter);

            if (index == -1)
            {
                for (int i = 0; i < customers.Count; i++)
                {
                    index = i;

                    if (letter < customers[i].LinkedCustomer.Name.ToLower()[0])
                        break;
                }
            }

            svWithPanel.ScrollToVerticalOffset(offset * index);
            svWithList.ScrollToVerticalOffset(offset * index);
        }

        private void StateHasChanged()
        {
            customers.ForEach(c => c.ScreenStateChanged());

            ResetSVGrid();

            switch (screenState)
            { 
                case ScreenState.CustomerList:
                    Background = no_panel_state_bg;
                    main_container.Children.Remove(svWithPanel);
                    main_container.Children.Add(svWithList);
                    if (panel != null) panel.MainContainer.Visibility = Visibility.Hidden;
                    headers.MainContainer.Visibility = Visibility.Visible;                    
                    break;
                default:
                    Background = panel_state_bg;
                    main_container.Children.Remove(svWithList);
                    main_container.Children.Add(svWithPanel);
                    if (Selected != null) panel.MainContainer.Visibility = Visibility.Visible;
                    headers.MainContainer.Visibility = Visibility.Hidden;
                    break;
            }

            FilterCustomers(last_ordering_parameter);
        }

        internal List<SVCustomerEntry> GetFilteredCustomersList()
        {
            IEnumerable<SVCustomerEntry> filtered_customers;

            if (searchBox.TextBox.Text != "")
            {
                var text = searchBox.TextBox.Text.ToLower();
                filtered_customers = customers.Where(c => c.LinkedCustomer.FullName.ToLower().Contains(text)
                    || c.LinkedCustomer.Phone.Contains(text)
                    || c.LinkedCustomer.Age.ToString().Contains(text)
                    || c.LinkedCustomer.Address.ToLower().Contains(text)
                    || c.LinkedCustomer.Email.ToLower().Contains(text)
                    || c.LinkedCustomer.Notes.ToLower().Contains(text));
            }
            else
                filtered_customers = customers;

            switch (last_ordering_parameter)
            {
                case FilterParameter.Name:
                    filtered_customers = filtered_customers.OrderBy(c => c.LinkedCustomer.FullName);
                    break;
                case FilterParameter.Phone:
                    filtered_customers = filtered_customers.OrderBy(c => c.LinkedCustomer.Phone);
                    break;
                case FilterParameter.Address:
                    filtered_customers = filtered_customers.OrderBy(c => c.LinkedCustomer.Address);
                    break;
                case FilterParameter.Age:
                    filtered_customers = filtered_customers.OrderBy(c => c.LinkedCustomer.Age);
                    break;
                    #warning Da modificare!
                case FilterParameter.Returned:
                    filtered_customers = filtered_customers.OrderBy(c => c.LinkedCustomer.Frequency);
                    break;
                case FilterParameter.None:
                    break;
            }

            return filtered_customers != null ? filtered_customers.ToList() : null;
        }

        internal void FilterCustomers(FilterParameter param)
        {
            IEnumerable<SVCustomerEntry> filtered_customers;

            if (searchBox.TextBox.Text != "")
            {
                var text = searchBox.TextBox.Text.ToLower();
                filtered_customers = customers.Where(c => c.LinkedCustomer.FullName.ToLower().Contains(text)
                    || c.LinkedCustomer.Phone.Contains(text)
                    || c.LinkedCustomer.Age.ToString().Contains(text)
                    || c.LinkedCustomer.Address.ToLower().Contains(text)
                    || c.LinkedCustomer.Email.ToLower().Contains(text)
                    || c.LinkedCustomer.Notes.ToLower().Contains(text));
            }
            else
                filtered_customers = customers;

            switch (param)
            {                
                case FilterParameter.Name:
                    ResetSVGrid();
                    filtered_customers = param != last_ordering_parameter ? 
                        filtered_customers.OrderBy(c => c.LinkedCustomer.FullName) :
                        filtered_customers.OrderByDescending(c => c.LinkedCustomer.FullName);
                    break;
                case FilterParameter.Phone:
                    ResetSVGrid();
                    filtered_customers = param != last_ordering_parameter ?
                        filtered_customers.OrderBy(c => c.LinkedCustomer.Phone) :
                        filtered_customers.OrderByDescending(c => c.LinkedCustomer.Phone);
                    break;
                case FilterParameter.Address:
                    ResetSVGrid();
                    filtered_customers = param != last_ordering_parameter ?
                        filtered_customers.OrderBy(c => c.LinkedCustomer.Address) :
                        filtered_customers.OrderByDescending(c => c.LinkedCustomer.Address);
                    break;
                case FilterParameter.Age:
                    ResetSVGrid();
                    filtered_customers = param != last_ordering_parameter ?
                        filtered_customers.OrderBy(c => c.LinkedCustomer.Age) :
                        filtered_customers.OrderByDescending(c => c.LinkedCustomer.Age);
                    break;
                #warning Da modificare!
                case FilterParameter.Returned:
                    ResetSVGrid();
                    filtered_customers = param != last_ordering_parameter ?
                        filtered_customers.OrderBy(c => c.LinkedCustomer.Frequency) :
                        filtered_customers.OrderByDescending(c => c.LinkedCustomer.Frequency);
                    break;
                case FilterParameter.None:
                    ResetSVGrid();
                    break;
            }

            if (filtered_customers != null)
            {
                var filtered_customers_list = filtered_customers.ToList();
                for (int i = 0; i < filtered_customers_list.Count; i++)
                {
                    switch (screenState)
                    {
                        case ScreenState.CustomerList:
                            AddCustomerToGrid(svWithListGrid, filtered_customers_list[i]);
                            break;
                        default:
                            AddCustomerToGrid(svWithPanelGrid, filtered_customers_list[i]);
                            break;
                    }
                }

                if (!filtered_customers_list.Contains(Selected)) Selected = null;
            }

            if (last_ordering_parameter == param)
                last_ordering_parameter = (FilterParameter)((int)param + 1);
            else
                last_ordering_parameter = param;
        }

        internal ScreenState State
        {
            get { return screenState; }
        }

        internal enum ScreenState
        {
            CustomerList,
            CustomerPanel
        }

        internal enum FilterParameter
        {
            None,
            Name,
            ReversedName,
            Phone,
            ReversedPhone,
            Address,
            ReversedAddress,
            Age,
            ReversedAge,
            Returned,
            ReversedReturned
        }
    }
}
